home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / applications / wp / xvi.lha / Xvi_V1.0_Src / amiga.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-04  |  74.9 KB  |  2,376 lines

  1. /* Copyright (c) 1990,1991,1992 Chris and John Downey; */
  2. /* Copyright (c) 1994 Dan Schmelzer                    */
  3.  
  4. /* Filename amiga.c       */
  5. /* Initial Date:  9/24/94 */
  6. /* Revised Date: 10/27/94 */
  7. /* Author: Dan Schmelzer  */
  8.  
  9. #ifndef lint
  10. static char *sccsid_amiga="@(#)amiga.c   2.1 (Dan Schmelzer) 10/27/94";
  11. #endif
  12.  
  13. /*______________________________________________________________________
  14. * program name:
  15.     xvi
  16. * function:
  17.     Portable version of UNIX "vi" editor, with extensions.
  18. * module name:
  19.     amiga.c
  20. * module function:
  21.     System interface module for the Amiga
  22. * history:
  23.     STEVIE - ST Editor for VI Enthusiasts, Version 3.10
  24.     Originally by Tim Thompson (twitch!tjt)
  25.     Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
  26.     Heavily modified by Chris & John Downey
  27.     Amiga porting started by Dougie for Lattice 6.0
  28.     Amiga modifications/porting by Dan Schmelzer for SAS 6.5
  29.     This file created by Dan Schmelzer
  30.  
  31. * Static functions defined in this file:
  32.       OpenConsole()
  33.       Init_IO()
  34.       Cleanup_IO()
  35.       WriteWindowTitle()
  36.       ResizeWindow()
  37.       QueueRead()
  38.       ConGetChar()
  39.       ConPutChar()
  40.       ConPutStr()
  41.       XviFindToolType()
  42.  
  43. * Global functions defined in this file:
  44.       inchar()
  45.       outchar()
  46.       outstr()
  47.       flush_output()
  48.       erase_display()
  49.       alert()
  50.       sleep()
  51.       delay()
  52.       amiga_sys_init()
  53.       sys_exit()
  54.       tty_goto()
  55.       sys_pipe()
  56.       call_system()
  57.       call_shell()
  58.       sys_startv()
  59.       sys_endv()
  60.       can_write()
  61.       set_colour()
  62.       tempfname()
  63.       exists()
  64.       amiga_version()
  65.  
  66. * DEBUG: undef DEBUG    No debug
  67.            def DEBUG=1  Minimal debug
  68.            def DEBUG=2  Medium amount of debug, no Output functions
  69.            def DEBUG=3  Large amount of debug, Output functions included
  70.            def DEBUG=4  Maximum debug information (lots)
  71.  
  72.          undef NO_OUT_BUFFERING  Normal output buffering.
  73.            def NO_OUT_BUFFERING  No output buffering for easier debug.
  74. ______________________________________________________________________*/
  75.  
  76. #include "xvi.h"
  77.  
  78. #if DEBUG > 1
  79. int ttygoto_count = 0;
  80. #endif
  81.  
  82. /*____________________________________________________________________*/
  83. /* AMIGA Version Strings.                                             */
  84.  
  85. #ifdef OLD_AMIGA_OS /*________________________________________________*/
  86. /* For pre-2.0 Amiga OS.  Must be short and sweet (about 58 cols). */
  87. char amiga_ver_str[] =
  88.  "Generic Xvi V2.15, Amiga Xvi V1.0  (for Amiga OS V1.3)";
  89.  
  90. #else /*______________________________________________________________*/
  91. /* For 2.0 and later Amiga OS. */
  92. char amiga_ver_str[] =
  93.  "Xvi Editor Copyright \251 1990,\n"
  94.  "1991, 1992 Chris & John Downey\n"
  95.  "\n"
  96.  "Amiga Conversion for Xvi Editor\n"
  97.  "Copyright \251 1994 Dan Schmelzer\n"
  98.  "\n"
  99.  "Generic Xvi Version: 2.15\n"
  100.  "  Amiga Xvi Version: 1.0\n"
  101.  "Amiga Version Built: " __DATE__;
  102. #endif /*_____________________________________________________________*/
  103.  
  104.  
  105. /*____________________________________________________________________*/
  106. /* These are globals which are set by the OS-specific module,         */
  107. /* and used for various purposes throughout the rest of xvi.          */
  108.  
  109. int Rows;        /* Number of Rows and Columns */
  110. int Columns;        /* in the current window. */
  111.  
  112.  
  113. /*____________________________________________________________________*/
  114. /* Library bases.  Variable names must not be altered.                */
  115.  
  116. struct DiskfontBase   *DiskfontBase = NULL;
  117. struct IntuitionBase  *IntuitionBase = NULL;
  118. struct GfxBase        *GfxBase = NULL;
  119.  
  120. /* DOSBase already defined in compiler startup code */
  121. extern struct DosLibrary *DOSBase;
  122.  
  123. /*____________________________________________________________________*/
  124. /* External system function declarations.                             */
  125.  
  126. extern APTR OpenLibrary();
  127. extern struct Screen    *OpenScreen();
  128. extern struct Window    *OpenWindow();
  129. extern struct MsgPort   *CreatePort();
  130. extern struct IOStdReq  *CreateStdIO();
  131. extern struct TextFont  *OpenDiskFont();
  132.  
  133. extern void  CloseLibrary();
  134. extern void  CloseScreen();
  135. extern void  CloseWindow();
  136. extern void  DeletePort();
  137. extern void  DeleteStdIO();
  138. extern void  CloseDevice();
  139. extern void  CloseFont();
  140. extern void  ActivateWindow();
  141.  
  142. extern void  LoadRGB4();
  143. extern long  SetFont();
  144. extern void  SendIO();
  145. extern long  DoIO();
  146. extern struct Message  *GetMsg();
  147. extern VirtScr defscr;
  148.  
  149. /*____________________________________________________________________*/
  150. /* Forward referencing for static functions defined in this file.     */
  151.  
  152. static int  OpenConsole();
  153. static int  Init_IO();
  154. static void Cleanup_IO();
  155. static void WriteWindowTitle();
  156. static void ResizeWindow();
  157. static void QueueRead();
  158. static int  ConGetChar();
  159. static void ConPutChar();
  160. static void ConPutStr();
  161. static char *XviFindToolType();
  162.  
  163.  
  164. /*____________________________________________________________________*/
  165. /* Global variables                                                   */
  166.  
  167. bool_t workbench = FALSE;  /* Was xvi started up via workbench? */
  168. bool_t map_ret_flag = FALSE;    /* Do we map "\r" to "\r0" for cmds? */
  169. bool_t repaint = FALSE;    /* Do we need to repaint display? */
  170. UBYTE *saved_title;    /* Saved window title if started up via CLI. */
  171. char readstring[4];    /* Use only first character. */
  172.  
  173. struct WBStartup *wb_startup;    /* Workbench startup stuff. */
  174. int *saved_argc_ptr;        /* Saved pointer to argc. */
  175. char ***saved_argv_ptr;        /* Saved pointer to argv. */
  176.  
  177. struct Window *xvi_window;
  178.  
  179. /* We start out with initial values that we think are safe. */
  180. struct NewWindow xvi_newwind =
  181. {
  182.   0,            /* Left Edge (filled in later) */
  183.   0,            /* Top Edge (filled in later)  */
  184.   INIT_WIDTH,        /* Width        */
  185.   INIT_HEIGHT,        /* Height       */
  186.   -1,            /* Detail Pen   */
  187.   -1,            /* Block Pen    */
  188.   0,            /* IDCMP Flags  */
  189.   WINDOWCLOSE | SMART_REFRESH | ACTIVATE | WINDOWDRAG |
  190.    WINDOWDEPTH | WINDOWSIZING | NOCAREREFRESH, /* Flags  */
  191.   NULL,            /* Gadgets      */
  192.   NULL,            /* Menu Check Mark */
  193.   "xvi window",        /* Title        */
  194.   NULL,            /* Screen       */
  195.   NULL,            /* SuperBitMap  */
  196.   1,            /* Min Width    */
  197.   1,            /* Min Height   */
  198.   10000,        /* Max Width    */
  199.   10000,        /* Max Height   */
  200.   WBENCHSCREEN        /* Screen Type  */
  201. };
  202.  
  203. struct IOStdReq *consoleWriteMsg;
  204. struct IOStdReq *consoleReadMsg;
  205.  
  206. struct MsgPort *consoleWritePort;
  207. struct MsgPort *consoleReadPort;
  208.  
  209. char out_buffer[OUT_BUFFER_SIZE+2];    /* Output display buffer. */
  210. int out_buf_index = 0;            /* Index into out_buffer. */
  211.  
  212. char *name_str = NULL;        /* For Workbench NAME Tool Type. */
  213. char *parms_str = NULL;        /* For Workbench PARMS Tool Type. */
  214.  
  215. char *font_str = NULL;            /* For custom font. */
  216. struct TextFont *tf = NULL;
  217. struct TextAttr ta;
  218.  
  219. int left_edge = 0; /* Pixels from left screen edge to left window edge*/
  220. int top_edge = 0;  /* Pixels from top screen edge to top window edge. */
  221.   
  222.  
  223. /* The follwing structures are for the "exit" requestor. */
  224.  
  225. #ifdef OLD_AMIGA_OS /*________________________________________________*/
  226.  
  227. /* For pre-2.0 Amiga OS. */
  228. /* (If this is used for 2.0 OS or later the only  */
  229. /*  part of the structure used is the text part.) */
  230.  
  231. struct IntuiText xvi_exit_bodytext =
  232. {
  233.   1,        /* Foreground color */
  234.   0,        /* Background color */
  235.   JAM2,        /* Draw mode */
  236.   6,        /* Left Edge */
  237.   3,        /* Top Edge */
  238.   NULL,        /* Text Attribute (use default) */
  239.   "Some Buffers Not Written!",
  240.   NULL        /* Next IntuiText */
  241. };
  242.   
  243. struct IntuiText xvi_exit_postext =
  244. {
  245.   1,0,JAM2,6,3,NULL,"EXIT Anyway",NULL
  246. };
  247.  
  248. struct IntuiText xvi_exit_negtext =
  249. {
  250.   1,0,JAM2,6,3,NULL,"RESUME Xvi",NULL
  251. };
  252.  
  253. struct IntuiText xvi_ver_bodytext =
  254. {
  255.   1,        /* Foreground color */
  256.   0,        /* Background color */
  257.   JAM2,        /* Draw mode */
  258.   6,        /* Left Edge */
  259.   3,        /* Top Edge */
  260.   NULL,        /* Text Attribute (use default) */
  261.   amiga_ver_str,
  262.   NULL        /* Next IntuiText */
  263. };
  264.  
  265. struct IntuiText xvi_ver_negtext =
  266. {
  267.   1,0,JAM2,6,3,NULL,"Continue",NULL
  268. };
  269.  
  270. #else /*______________________________________________________________*/
  271.  
  272. /* For 2.0 Amiga OS or later. */
  273. struct EasyStruct xvi_exit_requester =
  274. {
  275.   sizeof(struct EasyStruct),
  276.   0,
  277.   "Xvi Exit Request",
  278.   "Some Buffers Not Written!",
  279.   "EXIT Anyway|RESUME Xvi"
  280. };
  281.  
  282. /* For 2.0 Amiga OS or later. */
  283. struct EasyStruct xvi_ver_requester =
  284. {
  285.   sizeof(struct EasyStruct),
  286.   0,
  287.   "Xvi Version",
  288.   amiga_ver_str,
  289.   "Continue"
  290. };
  291. #endif /*_____________________________________________________________*/
  292.  
  293.  
  294. /*____________________________________________________________________*/
  295. /* OpenConsole()                                                      */
  296. /*   Routine to open a console device.  Zero is returned if ok.       */
  297. /*                                                                    */
  298. /* PARMS: Pointers to I/O request structures and Window structure.    */
  299. /* RETURNS: Error value from OpenDevice() call.                       */
  300. /*____________________________________________________________________*/
  301. /* FUNCTION */
  302.  
  303. static int OpenConsole(writerequest, readrequest, window)
  304.   struct IOStdReq  *writerequest;
  305.   struct IOStdReq  *readrequest;
  306.   struct Window    *window;
  307. {
  308.   int error;
  309.  
  310. #if DEBUG > 2
  311.   fprintf(stderr, "> OpenConsole()\n");
  312. #endif
  313.  
  314.   writerequest->io_Data = (APTR) window;
  315.   writerequest->io_Length = sizeof(struct Window);
  316.  
  317.   error = (int)OpenDevice("console.device", 0L, writerequest, 0L);
  318.   readrequest->io_Device = writerequest->io_Device;
  319.   readrequest->io_Unit = writerequest->io_Unit;
  320.  
  321. #ifdef DEBUG
  322.   fprintf(stderr, "< OpenConsole(): error=%d\n", error);
  323. #endif
  324.   return (error);
  325. }
  326.  
  327.  
  328. /*____________________________________________________________________*/
  329. /* Init_IO()                                                          */
  330. /*   Routine to open a screen, then open a window in it, and attach   */
  331. /*   the console device to it.                                        */
  332. /*                                                                    */
  333. /* RETURNS:  0  Operation successful                                  */
  334. /*           1  Failed to open graphics library                       */
  335. /*           2  Failed to open intuition library                      */
  336. /*           3  Failed to open diskfont library                       */
  337. /*           4  Failed to open DOS library                            */
  338. /*           5  Failed to open custom window                          */
  339. /*           6  Failed to load custom disk font                       */
  340. /*           7  Unable to change Min and Max size for custom window   */
  341. /*           8  Failed to create write port                           */
  342. /*           9  Failed to create standard out                         */
  343. /*          10  Failed to create read port                            */
  344. /*          11  Failed to create standard in                          */
  345. /*          12  Failed to open console device                         */
  346. /*____________________________________________________________________*/
  347. /* FUNCTION */
  348.  
  349. static int Init_IO()
  350. {
  351.   ULONG lockcall;
  352.   ULONG lock_number = 0;
  353.   int min_rows;
  354.   int min_columns;
  355.   int max_rows;
  356.   int max_columns;
  357.   int min_wind_width;
  358.   int min_wind_height;
  359.   int max_wind_width;
  360.   int max_wind_height;
  361.   int wind_width;
  362.   int wind_height;
  363.   int text_width;
  364.   int text_height;
  365.   int lr_border;
  366.   int tb_border;
  367.   int error = 0;
  368.   char *tmp_str;
  369.  
  370. #if DEBUG > 1
  371.   fprintf(stderr, "> Init_IO()\n");
  372. #endif
  373.  
  374.   out_buf_index = 0;  /* Let's just make sure buffer is set to empty. */
  375.  
  376.   if ((GfxBase = (struct GfxBase *)
  377.    OpenLibrary("graphics.library", LIB_REV)) == NULL)
  378.   {
  379.     error = 1;        /* Failed to open graphics library. */
  380. #ifndef OLD_AMIGA_OS /*_______________________________________________*/
  381.     printf("Unable to open graphics.library.\n"
  382.            "This software requires Amiga OS version 2.0 or later.\n");
  383. #endif /*_____________________________________________________________*/
  384.     goto exit_pt;
  385.   }
  386.  
  387.   if ((IntuitionBase = (struct IntuitionBase *)
  388.    OpenLibrary("intuition.library", LIB_REV)) == NULL)
  389.   {
  390.     error = 2;        /* Failed to open intuition library. */
  391.     goto exit_pt;
  392.   }
  393.  
  394.   if ((DiskfontBase = (struct DiskfontBase *)
  395.    OpenLibrary("diskfont.library", LIB_REV)) == NULL)
  396.   {
  397.     error = 3;        /* Failed to open diskfont library. */
  398.     goto exit_pt;
  399.   }
  400.  
  401.   if ((DOSBase = (struct DOSBase *)
  402.    OpenLibrary("dos.library", LIB_REV)) == NULL)
  403.   {
  404.     error = 4;        /* Failed to open DOS library. */
  405.     goto exit_pt;
  406.   }
  407.  
  408.   /* Get the Amiga window we'll be using. */
  409.   if (workbench)
  410.   {
  411.     /* Xvi was started from Workbench so create a new window. */
  412.     xvi_newwind.LeftEdge = left_edge;
  413.     xvi_newwind.TopEdge = top_edge;
  414.     if ((xvi_window = OpenWindow(&xvi_newwind)) == NULL)
  415.     {
  416.       error = 5;    /* Failed to open custom window. */
  417.       goto exit_pt;
  418.     }
  419.   }
  420.   else
  421.   {
  422.     /* Xvi was started from CLI so connect to existing window. */
  423.  
  424.     lockcall = LockIBase(lock_number);    /* Don't try to debug here... */
  425.     xvi_window = IntuitionBase->ActiveWindow;
  426.     UnlockIBase(lockcall);        /* ...to here.                */
  427.   }
  428.  
  429.   /* Only if the font has NOT been overriden by the workbench     */
  430.   /* tool type do we use the XVIFONT environment variable.        */
  431.   /*                                                              */
  432.   /* The XVIFONT environment variable or FONT tool type string    */
  433.   /* must be of the following formats:                            */
  434.   /*   [<font_path>]<font_name>.font,<size>                       */
  435.   /*   [<font_path>]<font_name>.font <size>                       */
  436.   /*                                                              */
  437.   /* For example:                                                 */
  438.   /*   Fonts:topaz.font,8                                         */
  439.   /*   topaz.font 16                                              */
  440.   /*   FONT=topaz.font,16     (workbench tool type for xvi)       */
  441.  
  442.   /* Get the XVIFONT environment variable, if it exists */
  443.   if (!font_str)
  444.     font_str = getenv("XVIFONT");
  445.  
  446.   /* If specified, load a custom font. */
  447.   if (font_str)
  448.   {
  449.     char *str_ptr = font_str;
  450.  
  451.     /* Find ',' */
  452.     while (*str_ptr && (*str_ptr != ',') && (*str_ptr != ' '))
  453.       str_ptr++;
  454.  
  455.     if (*str_ptr)
  456.     {
  457.       *str_ptr = '\000';    /* Terminate Name part of font string.*/
  458.  
  459.       /* Attributes of font to load. */
  460.       ta.ta_Name = font_str;
  461.       ta.ta_YSize = atoi(str_ptr + 1);    /* Get font size. */
  462.       ta.ta_Style = 0;
  463.       ta.ta_Flags = FPF_DISKFONT;
  464.  
  465.       /* Load the special font. */
  466.       if ((tf = (struct TextFont *)OpenDiskFont(&ta)) == NULL)
  467.       {
  468.         printf("Unable to load font \"%s\" size %d\n",
  469.                ta.ta_Name, ta.ta_YSize);
  470.         error = 6;    /* Failed to open disk font. */
  471.         goto exit_pt;
  472.       }
  473.       SetFont(xvi_window->RPort, tf);    /* Attach font to window. */
  474.     }
  475.     else
  476.     {
  477.       printf("Bad font definition string in XVIFONT: \"%s\"\n",
  478.               font_str);
  479.       error = 6;    /* Failed to open disk font. */
  480.       goto exit_pt;
  481.     }
  482.   }
  483.  
  484.   /* Now resize the Amiga window as needed to get everything all ok. */
  485.   if (workbench)
  486.   {
  487.     /* Note that the Rows and Columns variables have already been set */
  488.     /* by the amiga_sys_init() routine before this.                   */
  489.  
  490.     /* Start off with default min and max sizes. */
  491.     min_rows = MIN_ROWS;
  492.     min_columns = MIN_COLS; /* May be overriden if too small. */
  493.     max_rows = MAX_ROWS;
  494.     max_columns = MAX_COLS;
  495.  
  496.     /* Get Text size. */
  497.     text_width = xvi_window->RPort->TxWidth;
  498.     text_height = xvi_window->RPort->TxHeight;
  499.  
  500.     /* Make sure text width is no less than 4 times right border to   */
  501.     /* guarantee that window system gadets are visible when minimized.*/
  502.     if ((text_width * min_columns) < (4 * xvi_window->BorderRight))
  503.     {
  504.       /* Recalculate minimum number of columns. */
  505.       min_columns = ((4 * xvi_window->BorderRight) / text_width) + 1;
  506.     }
  507.  
  508.     /* Get borders. */
  509.     lr_border = xvi_window->BorderLeft + xvi_window->BorderRight;
  510.     tb_border = xvi_window->BorderTop + xvi_window->BorderBottom;
  511.  
  512.     /* Set up actual window dimensions based on rows and columns. */
  513.     min_wind_width = (text_width * min_columns) + lr_border;
  514.     min_wind_height = (text_height * min_rows) + tb_border;
  515.     max_wind_width = (text_width * max_columns) + lr_border;
  516.     max_wind_height = (text_height * max_rows) + tb_border;
  517.     wind_width = (text_width * Columns) + lr_border;
  518.     wind_height = (text_height * Rows) + tb_border;
  519.  
  520.     /* First resize window based on Row and Column. */
  521.     SizeWindow(xvi_window, (wind_width - xvi_window->Width),
  522.                (wind_height - xvi_window->Height));
  523.  
  524.     /* Now adjust window size limits to nominal values. */
  525.     if (!WindowLimits(xvi_window, min_wind_width, min_wind_height,
  526.                      max_wind_width, max_wind_height))
  527.     {
  528.       printf("Unable to change Min and Max size of window.\n"
  529.              "Font used may be too large or too small.\n");
  530.       error = 7;    /* Call to WindowLimits() Failed. */
  531.       goto exit_pt;
  532.     }
  533.   }
  534.   else
  535.   {
  536.     /* Xvi was started from CLI so calculate rows and columns from */
  537.     /* existing CLI window.                                        */
  538.  
  539.     /* Get window border size. */
  540.     lr_border = xvi_window->BorderLeft + xvi_window->BorderRight;
  541.     tb_border = xvi_window->BorderTop + xvi_window->BorderBottom;
  542.  
  543.     /* Calculate Columns and Rows based on size of existing window. */
  544.     Columns = (xvi_window->Width - lr_border) /
  545.                xvi_window->RPort->TxWidth;
  546.     Rows = (xvi_window->Height - tb_border) /
  547.             xvi_window->RPort->TxHeight;
  548.  
  549.     saved_title = xvi_window->Title;    /* Save original window title.*/
  550.   }
  551.  
  552.   /* Change the window title to show how many rows and columns. */
  553.   WriteWindowTitle();
  554.  
  555.   if ((consoleWritePort = CreatePort("xvi.con.write",0L)) == NULL)
  556.   {
  557.     error = 8;        /* Failed to create console write port. */
  558.     goto exit_pt;
  559.   }
  560.  
  561.   if ((consoleWriteMsg = CreateStdIO(consoleWritePort)) == NULL)
  562.   {
  563.     error = 9;        /* Failed to create standard out. */
  564.     goto exit_pt;
  565.   }
  566.  
  567.   if ((consoleReadPort = CreatePort("xvi.con.read",0L)) == NULL)
  568.   {
  569.     error = 10;        /* Failed to create console read port. */
  570.     goto exit_pt;
  571.   }
  572.  
  573.   if ((consoleReadMsg = CreateStdIO(consoleReadPort)) == NULL)
  574.   {
  575.     error = 11;        /* Failed to create standard in. */
  576.     goto exit_pt;
  577.   }
  578.  
  579.   if (OpenConsole(consoleWriteMsg,consoleReadMsg,xvi_window) != 0)
  580.   {
  581.     error = 12;        /* Failed to open console device. */
  582.     goto exit_pt;
  583.   }
  584.  
  585.   QueueRead();        /* Queue up first read. */
  586.  
  587.   outstr("\2332{");    /* Ask for RAW event: Mouse Info. */
  588.   outstr("\23312{");    /* Ask for RAW event: Window Resize. */
  589.   outstr("\23311{");    /* Ask for RAW event: Close Gadget. */
  590.   if(!workbench)
  591.     outstr("\23313{");    /* Ask for RAW event: Window Refreshed. */
  592.  
  593.   flush_output();    /* Flush the above output. */
  594.  
  595.   /* Check for existance of XVIMAP_RET environment variable.    */
  596.   /* If it exists we want to map "\r" to "\r0" while in NORMAL  */
  597.   /* mode.  This is not possible thru the normal "map" command. */
  598.   if (tmp_str = getenv("XVIMAP_RET"))
  599.   {
  600.     map_ret_flag = TRUE;
  601.     free(tmp_str);    /* Clean up from getenv(). */
  602.   }
  603.   else
  604.     map_ret_flag = FALSE;
  605.  
  606. #if DEBUG > 1
  607.   fprintf(stderr, "  Init_IO(): Window Information:\n");
  608.   fprintf(stderr, "    Left Edge=%d, Top Edge=%d\n",
  609.           xvi_window->LeftEdge, xvi_window->TopEdge);
  610.   fprintf(stderr, "    Width=%d, Height=%d\n",
  611.           xvi_window->Width, xvi_window->Height);
  612.   fprintf(stderr, "    Min Width=%d, Min Height=%d\n",
  613.           xvi_window->MinWidth, xvi_window->MinHeight);
  614.   fprintf(stderr, "    Max Width=%d, Max Height=%d\n",
  615.           xvi_window->MaxWidth, xvi_window->MaxHeight);
  616.   fprintf(stderr, "    Border Left=%d, Border Right=%d\n",
  617.           xvi_window->BorderLeft, xvi_window->BorderRight);
  618.   fprintf(stderr, "    Border Top=%d, Border Bottom=%d\n",
  619.           xvi_window->BorderTop, xvi_window->BorderBottom);
  620.   fprintf(stderr, "    Text Width=%d, Text Height=%d\n",
  621.           xvi_window->RPort->TxWidth, xvi_window->RPort->TxHeight);
  622. #endif
  623.  
  624. exit_pt:
  625.  
  626. #if DEBUG > 1
  627.   fprintf(stderr, "< Init_IO(): error=%d\n", error);
  628. #endif
  629.   return (error);
  630. }
  631.  
  632.  
  633. /*____________________________________________________________________*/
  634. /* Cleanup_IO()                                                       */
  635. /*   Routine to cleanup by closing the console device, ports,         */
  636. /*   I/O streams, the custom window, the custom screen, and libraries.*/
  637. /*                                                                    */
  638. /* PARMS: err - This is the result of Init_IO() call and is used to   */
  639. /*              determine how much stuff needs to be unraveled.       */
  640. /*____________________________________________________________________*/
  641. /* FUNCTION */
  642.  
  643. static void Cleanup_IO(err)
  644.   int err;
  645. {
  646. #ifdef DEBUG
  647.   fprintf(stderr, "> Cleanup_IO(): err=%d\n", err);
  648. #endif
  649.  
  650.   switch(err)
  651.   {
  652.     case 0:
  653.       CloseDevice(consoleWriteMsg);    /* Close the console device. */
  654.     case 12:
  655.       DeleteStdIO(consoleReadMsg);    /* Delete standard in. */
  656.     case 11:
  657.       DeletePort(consoleReadPort);    /* Delete console read port. */
  658.     case 10:
  659.       DeleteStdIO(consoleWriteMsg);    /* Delete standard out. */
  660.     case 9:
  661.       DeletePort(consoleWritePort);    /* Delete console write port. */
  662.     case 8:
  663.     case 7:
  664.       if (font_str)
  665.         CloseFont(tf);            /* Close any custom disk font.*/
  666.     case 6:
  667.       /* Free any memory gotten via getenv() or getmem(). */
  668.       if (font_str)
  669.         free(font_str);
  670.  
  671.       if (workbench)
  672.       {
  673.         /* Xvi was started from Workbench so close the xvi window. */
  674.         CloseWindow(xvi_window);    /* Close custom window. */
  675.       }
  676.       else
  677.       {
  678.         /* Restore original CLI window title.*/
  679.         xvi_window->Title = saved_title;
  680.  
  681.         /* Reactivate window for use by CLI. */
  682.         /* First have to unselect window. Do this by selecting it's */
  683.         /* parent.  Then select the window.                         */
  684.         if (xvi_window->Parent)
  685.           ActivateWindow(xvi_window->Parent);
  686.         ActivateWindow(xvi_window);
  687.         printf("\014");            /* Erase the CLI screen. */
  688.       }
  689.     case 5:
  690.       CloseLibrary(DOSBase);         /* Close DOS library. */
  691.     case 4:
  692.       CloseLibrary(DiskfontBase);    /* Close diskfont library. */
  693.     case 3:
  694.       CloseLibrary(IntuitionBase);    /* Close intuition library. */
  695.     case 2:
  696.       CloseLibrary(GfxBase);        /* Close graphics library. */
  697.     case 1:
  698.   }
  699.  
  700. #if DEBUG > 2
  701.   fprintf(stderr, "< Cleanup_IO()\n");
  702. #endif
  703. }
  704.  
  705.  
  706. /*____________________________________________________________________*/
  707. /* WriteWindowTitle()                                                 */
  708. /*   Routine to write the current window's title.                     */
  709. /*____________________________________________________________________*/
  710. /* FUNCTION */
  711.  
  712. static void WriteWindowTitle()
  713. {
  714.   static char title_str[MAX_NAME_LENGTH + 24]; 
  715.   char *name;
  716.  
  717.   if (name_str)
  718.   {
  719.     name = name_str;
  720.  
  721.     /* Truncate name if necessary. */
  722.     if (strlen(name) > MAX_NAME_LENGTH)
  723.       *(name + MAX_NAME_LENGTH) = '\000';
  724.   }
  725.   else
  726.     name = "xvi";
  727.  
  728.   /* Change the window title to show how many rows and columns. */
  729.   (void)sprintf(title_str, "%s %dx%d window", name, Rows, Columns);
  730.   SetWindowTitles(xvi_window, title_str, -1);
  731. }
  732.  
  733.  
  734. /*____________________________________________________________________*/
  735. /* ResizeWindow()                                                     */
  736. /*   Do all the goo to resize not only the display but also to        */
  737. /*   get the generic part of xvi to work with new Row and Column      */
  738. /*   values.                                                          */
  739. /*____________________________________________________________________*/
  740. /* FUNCTION */
  741.  
  742. static void ResizeWindow()
  743. {
  744.   int min_rows;
  745.   int new_columns;
  746.   int new_rows;
  747.   int delta_columns;
  748.   int delta_rows;
  749.   int wind_width;
  750.   int wind_height;
  751.   int text_width;
  752.   int text_height;
  753.   int lr_border;
  754.   int tb_border;
  755.   Xviwin  *temp_win;
  756.  
  757. #if DEBUG > 2
  758.   fprintf(stderr, "> ResizeWindow()\n");
  759. #endif
  760.  
  761.   /* Get text size and border size. */
  762.   text_width = xvi_window->RPort->TxWidth;
  763.   text_height = xvi_window->RPort->TxHeight;
  764.   lr_border = xvi_window->BorderLeft + xvi_window->BorderRight;
  765.   tb_border = xvi_window->BorderTop + xvi_window->BorderBottom;
  766.  
  767.   /* Temporarily turning off RAW event "Window Resize" around   */
  768.   /* 2nd resize does not seem to keep from getting us into an   */
  769.   /* infinite loop, so we break the cycle by checking if resize */
  770.   /* will change row or column.  If not we don't do the resize. */
  771.  
  772.   /* Recalculate Columns and Rows based on new size of window. */
  773.   new_columns = (xvi_window->Width - lr_border) / text_width;
  774.   new_rows = (xvi_window->Height - tb_border) / text_height;
  775.  
  776.   if (new_columns != Columns || new_rows != Rows)
  777.   {
  778.     /* Calculate the minimum number of rows we can have.        */
  779.     /* This will be all other virtual window row counts plus 2. */
  780.     min_rows = (Rows - curwin->w_nrows) + 2;
  781.  
  782.     /* Make sure we don't try to resize too small vertically. */
  783.     if (new_rows < min_rows)
  784.       new_rows = min_rows;
  785.  
  786.     /* Calculate how row and column counts have changed. */
  787.     delta_columns = new_columns - Columns;
  788.     delta_rows = new_rows - Rows;
  789.  
  790.     /* Update the globals. */
  791.     Columns = new_columns;
  792.     Rows = new_rows;
  793.  
  794.     /* Now resize window again based on Row and Column to correct */
  795.     /* for any inacuracies when resizing window with gadget.      */
  796.     wind_width = (text_width * Columns) + lr_border;
  797.     wind_height = (text_height * Rows) + tb_border;
  798.  
  799.     SizeWindow(xvi_window, (wind_width - xvi_window->Width),
  800.                (wind_height - xvi_window->Height));
  801.  
  802.     WriteWindowTitle();        /* Update the window's title. */
  803.  
  804.     /* Now tell the generic part of xvi about what we've done. */
  805.  
  806.     /* Update the screen structure directly. */
  807.     defscr.pv_rows = Rows;
  808.     defscr.pv_cols = Columns;
  809.  
  810.     /* Update the virtual window(s) structures. */
  811.     /* Note that virtual window may not fill full virtual screen so   */
  812.     /* we must change curwin's w_nrows and w_ncols by the difference. */
  813.     curwin->w_nrows += delta_rows;
  814.     curwin->w_ncols += delta_columns;
  815.     curwin->w_cmdline += delta_rows;
  816.  
  817.     /* Adjust the width of ALL other virtual windows. */
  818.     temp_win = curwin;
  819.     while(temp_win = temp_win->w_next)
  820.     {
  821.       temp_win->w_ncols += delta_columns;
  822.     }
  823.     temp_win = curwin;
  824.     while(temp_win = temp_win->w_last)
  825.     {
  826.       temp_win->w_ncols += delta_columns;
  827.     }
  828.  
  829.     /* Update the real screen data structures. */
  830.     init_screen(curwin);
  831.  
  832.     /* Tell any file buffers to refresh their window/screen. */
  833.     update_buffer(curbuf);
  834.  
  835.     redraw_screen();        /* Redraw the screen. */
  836.  
  837.     move_window_to_cursor(curwin);
  838.     cursupdate(curwin);        /* Update the cursor. */
  839.     wind_goto(curwin);
  840.  
  841. #ifdef DEBUG
  842.     fprintf(stderr, "  ResizeWindow(): Window has been resized.\n");
  843. #endif
  844.   }
  845. #if DEBUG > 3
  846.   fprintf(stderr, "< ResizeWindow()\n");
  847. #endif
  848. }
  849.  
  850.  
  851. /*____________________________________________________________________*/
  852. /* QueueRead()                                                        */
  853. /*   Routine to queue up a read request to the console, show where to */
  854. /*   put the character when ready to be returned. Should be first     */
  855. /*   called just after opening the console.                           */
  856. /*                                                                    */
  857. /* SIDEEFFECTS:  consoleReadMsg                                       */
  858. /*____________________________________________________________________*/
  859. /* FUNCTION */
  860.  
  861. static void QueueRead()
  862. {
  863. #if DEBUG > 3
  864.   fprintf(stderr, "> QueueRead()\n");
  865. #endif
  866.   consoleReadMsg->io_Command = CMD_READ;
  867.   consoleReadMsg->io_Data = (APTR)&readstring[0];
  868.   consoleReadMsg->io_Length = 1;
  869.   SendIO(consoleReadMsg);
  870. #if DEBUG > 3
  871.   fprintf(stderr, "< QueueRead()\n");
  872. #endif
  873. }
  874.  
  875.  
  876. /*____________________________________________________________________*/
  877. /* ConGetChar()                                                       */
  878. /*   Routine to get a character from standard in.  It will wait if    */
  879. /*   necessary (task is put to sleep).                                */
  880. /*                                                                    */
  881. /* PARMS: cursor_on   Make cursor visible during keyboard input flag. */
  882. /* RETURNS: Integer holding character.                                */
  883. /*____________________________________________________________________*/
  884. /* FUNCTION */
  885.  
  886. static int ConGetChar(cursor_on)
  887.   bool_t cursor_on;
  888. {
  889.   int inputchar;
  890.  
  891. #if DEBUG > 3
  892.   fprintf(stderr, "> ConGetChar(): cursor_on=%d\n", cursor_on);
  893. #endif
  894.  
  895.   if (cursor_on)
  896.   {
  897.     vis_cursor();    /* Turn on the cursor while waiting for input.*/
  898.     flush_output();
  899.   }
  900.  
  901.   while (GetMsg(consoleReadPort) == NULL)
  902.     WaitPort(consoleReadPort);
  903.   inputchar = (UBYTE)readstring[0];    /* Get waiting character. */
  904.   QueueRead();            /* Queue up another read request. */
  905.  
  906.   if (cursor_on)
  907.     invis_cursor();    /* Since we turned cursor on, now turn it off.*/
  908.  
  909. #if DEBUG > 2
  910.   fprintf(stderr, "< ConGetChar(): inputchar=0x%02x='%c'\n",
  911.    inputchar, inputchar);
  912. #endif
  913.   return (inputchar);
  914. }
  915.  
  916.  
  917. /*____________________________________________________________________*/
  918. /* ConPutChar()                                                       */
  919. /*   Routine to send 1 character thru standard out to the custom      */
  920. /*   window.                                                          */
  921. /*                                                                    */
  922. /* PARMS: character                                                   */
  923. /*____________________________________________________________________*/
  924. /* FUNCTION */
  925.  
  926. static void ConPutChar(outputchar)
  927.   char outputchar;
  928. {
  929. #if DEBUG > 2
  930.   fprintf(stderr, "> ConPutChar(): outputchar=0x%02x='%c'\n",
  931.    outputchar, outputchar);
  932. #endif
  933.   consoleWriteMsg->io_Command = CMD_WRITE;
  934.   consoleWriteMsg->io_Data = (APTR)&outputchar;
  935.   consoleWriteMsg->io_Length = 1;
  936.   DoIO(consoleWriteMsg);    /* DoIO blocks until command is done. */
  937. #if DEBUG > 3
  938.   fprintf(stderr, "< ConPutChar()\n");
  939. #endif
  940. }
  941.  
  942.  
  943. /*____________________________________________________________________*/
  944. /* ConPutStr()                                                        */
  945. /*   Routine to send a null terminated string thru standard out to    */
  946. /*   the custom window.                                               */
  947. /*                                                                    */
  948. /* PARMS: string                                                      */
  949. /*____________________________________________________________________*/
  950. /* FUNCTION */
  951.  
  952. static void ConPutStr(string)
  953.   char *string;
  954. {
  955. #if DEBUG > 2
  956.   /* Print leading <CSI>.  Skip any other leading non-printable. */
  957.   fprintf(stderr, "> ConPutStr(): string=\"%s%s\"\n",
  958.    (*string == '\233') ? "<CSI>" : "",
  959.    (*string < ' ' || *string > '~') ? string+1 : string);
  960. #endif
  961.   consoleWriteMsg->io_Command = CMD_WRITE;
  962.   consoleWriteMsg->io_Data = (APTR)string;
  963.   consoleWriteMsg->io_Length = -1; /* End when find terminating zero. */
  964.   DoIO(consoleWriteMsg);    /* DoIO blocks until command is done. */
  965. #if DEBUG > 3
  966.   fprintf(stderr, "< ConPutStr()\n");
  967. #endif
  968. }
  969.  
  970.  
  971. /*____________________________________________________________________*/
  972. /* XviFindToolType()                                                  */
  973. /*   Routine similar to the Amiga OS routine FindToolType() except    */
  974. /*   that _WBArgc and _WBArgv are used from the SAS "C" startup       */
  975. /*   environment.  This makes life a lot easier.                      */
  976. /*                                                                    */
  977. /*   WARNING: This routine may be called only if we started via       */
  978. /*            workbench!                                              */
  979. /*                                                                    */
  980. /* PARMS: tool_name  Name of tool to search for (should end with '=').*/
  981. /* RETURNS: Pointer to string value associated with "tool_name" or    */
  982. /*           NULL if "tool_name" is not found.                        */
  983. /*____________________________________________________________________*/
  984. /* FUNCTION */
  985.  
  986. static char *XviFindToolType(tool_name)
  987.   char *tool_name;
  988. {
  989.   int i;
  990.   int size = strlen(tool_name);
  991.  
  992.   /* Search Workbench arguments. Skip first argument since we know */
  993.   /* it is not a Tool Type.                                        */
  994.   for(i = 1; i < _WBArgc; i++)
  995.   {
  996.     if (strncmp(tool_name, _WBArgv[i], size) == 0)
  997.     {
  998.       return(_WBArgv[i] + size);  /* Found tool_name, return string. */
  999.     }
  1000.   }
  1001.  
  1002.   return(NULL);        /* Did not find tool_name. */
  1003. }
  1004.  
  1005.  
  1006. /*____________________________________________________________________*/
  1007. /* inchar()                                                           */
  1008. /*   Get a character from the keyboard (console device).              */
  1009. /*   Do any remapping of characters and trapping of special           */
  1010. /*   characters in this routine.                                      */
  1011. /*                                                                    */
  1012. /* PARMS: timeout  (DAS - not handled at this time)                   */
  1013. /* RETURNS: Integer holding character.                                */
  1014. /*____________________________________________________________________*/
  1015. /* FUNCTION */
  1016.  
  1017. int inchar(timeout)
  1018.   long  timeout;
  1019. {
  1020.   static char *special_buffer = NULL;
  1021.   int input_char;
  1022.   bool_t special_key = FALSE;
  1023.  
  1024. #if DEBUG > 2
  1025.   fprintf(stderr, "> inchar(): timeout=%d\n", timeout);
  1026. #endif
  1027.  
  1028.   /* Check if an Amiga requestor has possibly messed up the display. */
  1029.   if (repaint)
  1030.   {
  1031.     /* We need to repaint window (with CNTL-L). */
  1032.     special_buffer = "\033\014";
  1033.     repaint = FALSE;
  1034.   }
  1035.  
  1036.   /* Get a character and check for <CSI>. Turn cursor on during input.*/
  1037.   while (!special_buffer &&
  1038.          (input_char = ConGetChar(TRUE)) == (UBYTE)'\233')
  1039.   {
  1040.     int input_char1;
  1041.     int input_char2 = 0;
  1042.     int input_char3 = 0;
  1043.  
  1044.     /* Get next 1, 2, or 3 characters as required. */
  1045.     input_char1 = ConGetChar(FALSE);
  1046.     switch ((char)input_char1)
  1047.     {
  1048.       case '1':
  1049.         input_char2 = ConGetChar(FALSE);
  1050.         switch ((char)input_char2)
  1051.         {
  1052.           case '0':    /* <CSI>10 */
  1053.           case '1':    /* <CSI>11 */
  1054.           case '2':    /* <CSI>12 */
  1055.           case '3':    /* <CSI>13 */
  1056.           case '4':    /* <CSI>14 */
  1057.           case '5':    /* <CSI>15 */
  1058.           case '6':    /* <CSI>16 */
  1059.           case '7':    /* <CSI>17 */
  1060.           case '8':    /* <CSI>18 */
  1061.           case '9':    /* <CSI>19 */
  1062.             input_char3 = ConGetChar(FALSE);
  1063.             if ((char)input_char3 == '~')
  1064.               special_key = TRUE;
  1065.             break;
  1066.  
  1067.           case '~':    /* <CSI>1~ */
  1068.             special_key = TRUE;
  1069.         }
  1070.         break;
  1071.  
  1072.       case '0':        /* <CSI>0 */
  1073.       case '2':        /* <CSI>2 */
  1074.       case '3':        /* <CSI>3 */
  1075.       case '4':        /* <CSI>4 */
  1076.       case '5':        /* <CSI>5 */
  1077.       case '6':        /* <CSI>6 */
  1078.       case '7':        /* <CSI>7 */
  1079.       case '8':        /* <CSI>8 */
  1080.       case '9':        /* <CSI>9 */
  1081.       case '?':        /* <CSI>? */
  1082.         input_char2 = ConGetChar(FALSE);
  1083.         if ((char)input_char2 == '~')
  1084.           special_key = TRUE;
  1085.         break;
  1086.  
  1087.       case ' ':
  1088.         input_char2 = ConGetChar(FALSE);
  1089.         if (((char)input_char2 == 'A') ||    /* <CSI> A */
  1090.             ((char)input_char2 == '@'))        /* <CSI> @ */
  1091.           special_key = TRUE;
  1092.         break;
  1093.  
  1094.       case 'A':        /* <CSI>A */
  1095.       case 'B':        /* <CSI>B */
  1096.       case 'C':        /* <CSI>C */
  1097.       case 'D':        /* <CSI>D */
  1098.       case 'S':        /* <CSI>S */
  1099.       case 'T':        /* <CSI>T */
  1100.         special_key = TRUE;
  1101.     }
  1102.  
  1103.     /* First check for Function, Help, or Arrow keys and map them. */
  1104.  
  1105.     /* Look for a special key. */
  1106.     if (special_key)
  1107.     {
  1108.       switch ((char)input_char1)
  1109.       {
  1110.         case '1':
  1111.           switch ((char)input_char2)
  1112.           {
  1113.             case '0':
  1114.               special_buffer = "\001p"; break;    /* Shifted F1 */
  1115.             case '1': 
  1116.               special_buffer = "\001q"; break;    /* Shifted F2 */
  1117.             case '2':
  1118.               special_buffer = "\001r"; break;    /* Shifted F3 */
  1119.             case '3':
  1120.               special_buffer = "\001s"; break;    /* Shifted F4 */
  1121.             case '4':
  1122.               special_buffer = "\001t"; break;    /* Shifted F5 */
  1123.             case '5':
  1124.               special_buffer = "\001u"; break;    /* Shifted F6 */
  1125.             case '6':
  1126.               special_buffer = "\001v"; break;    /* Shifted F7 */
  1127.             case '7':
  1128.               special_buffer = "\001w"; break;    /* Shifted F8 */
  1129.             case '8':
  1130.               special_buffer = "\001x"; break;    /* Shifted F9 */
  1131.             case '9':
  1132.               special_buffer = "\001y"; break;    /* Shifted F10 */
  1133.             case '~':
  1134.               special_buffer = "\001Q"; break;    /* F2 */
  1135.           }
  1136.           break;
  1137.  
  1138.         case '0':
  1139.           special_buffer = "\001P"; break;    /* F1 */
  1140.         case '2':
  1141.           special_buffer = "\001R"; break;    /* F3 */
  1142.         case '3':
  1143.           special_buffer = "\001S"; break;    /* F4 */
  1144.         case '4':
  1145.           special_buffer = "\001T"; break;    /* F5 */
  1146.         case '5':
  1147.           special_buffer = "\001U"; break;    /* F6 */
  1148.         case '6':
  1149.           special_buffer = "\001V"; break;    /* F7 */
  1150.         case '7':
  1151.           special_buffer = "\001W"; break;    /* F8 */
  1152.         case '8':
  1153.           special_buffer = "\001X"; break;    /* F9 */
  1154.         case '9':
  1155.           special_buffer = "\001Y"; break;    /* F10 */
  1156.         case '?':
  1157.           special_buffer = "\001?"; break;    /* Help */
  1158.         case 'A':
  1159.           special_buffer = "\001A"; break;    /* Up Arrow */
  1160.         case 'B':
  1161.           special_buffer = "\001B"; break;    /* Down Arrow */
  1162.         case 'C':
  1163.           special_buffer = "\001C"; break;    /* Right Arrow */
  1164.         case 'D':
  1165.           special_buffer = "\001D"; break;    /* Left Arrow */
  1166.         case 'T':
  1167.           special_buffer = "\001a"; break;    /* Shift Up Arrow */
  1168.         case 'S':
  1169.           special_buffer = "\001b"; break;    /* Shift Down Arrow */
  1170.  
  1171.         case ' ':
  1172.           switch ((char)input_char2)
  1173.           {
  1174.             case '@':
  1175.               special_buffer = "\001c"; break;    /* Shift Right Arrow */
  1176.             case 'A':
  1177.               special_buffer = "\001d";        /* Shift Left Arrow */
  1178.           }
  1179.       }
  1180.     } /* ...Look for a special key. */
  1181.     else 
  1182.     {
  1183.       /* Look for Resize Window event. */
  1184.       if (input_char1 == (UBYTE)'1' &&
  1185.           input_char2 == (UBYTE)'2' &&
  1186.           input_char3 == (UBYTE)';')
  1187.       {
  1188.         /* Wait for end of event sequence.*/
  1189.         while (ConGetChar(FALSE) != (UBYTE)'|');
  1190.   
  1191.         ResizeWindow();        /* Resize the window. */
  1192.       }
  1193.       else
  1194.       {
  1195.         /* Look for Close Window event. */
  1196.         if (input_char1 == (UBYTE)'1' &&
  1197.             input_char2 == (UBYTE)'1' &&
  1198.             input_char3 == (UBYTE)';')
  1199.         {
  1200.           Xviwin *wp;
  1201.           bool_t changed;
  1202.  
  1203.           /* Wait for end of event sequence.*/
  1204.           while (ConGetChar(FALSE) != (UBYTE)'|');
  1205.  
  1206.   #ifdef DEBUG
  1207.           fprintf(stderr, "  inchar(): Attempting to close window.\n");
  1208.   #endif
  1209.  
  1210.           /* First check to see if any xvi window contains */
  1211.           /* changes that have not been saved.             */
  1212.           changed = FALSE;
  1213.       wp = curwin;
  1214.       do
  1215.           {
  1216.             if (is_modified(wp->w_buffer))
  1217.             {
  1218.               changed = TRUE;
  1219.               break;
  1220.             }
  1221.           } while ((wp = next_window(wp)) != curwin);
  1222.  
  1223.       if (changed)
  1224.           {
  1225.             /* Display "exit" requestor if there were changes. */
  1226. #ifdef OLD_AMIGA_OS /*________________________________________________*/
  1227.             /* For pre-2.0 Amiga OS.  Last two numbers       */
  1228.             /* are for pre-2.0 OS requestor size parameters. */
  1229.             if (AutoRequest(xvi_window, xvi_exit_bodytext,
  1230.                             xvi_exit_postext, xvi_exit_negtext,
  1231.                             0, 0, 320, 50))
  1232. #else /*______________________________________________________________*/
  1233.             /* For 2.0 Amiga OS or later. */
  1234.             if (EasyRequestArgs(xvi_window, xvi_exit_requester,
  1235.                                 NULL, NULL) == 1)
  1236. #endif /*_____________________________________________________________*/
  1237.             {
  1238.               special_buffer = "\033:q!\015";    /* EXIT Anyway. */
  1239.             }
  1240.             else    /* Just repaint window with CNTL-L. */
  1241.               special_buffer = "\033\014";
  1242.           }
  1243.           else        /* Exit, buffers do not need saving. */
  1244.             special_buffer = "\033:q\015";
  1245.         }
  1246.         else
  1247.         {
  1248.           /* Check for mouse event. */
  1249.           if (input_char1 == (UBYTE)'2' &&
  1250.               input_char2 == (UBYTE)';')
  1251.           {
  1252.             int mouse_x;
  1253.             int mouse_y;
  1254.             int border_left;
  1255.             int border_top;
  1256.             int text_width;
  1257.             int text_height;
  1258.             int new_row;    /* New row for cursor. */
  1259.             int new_column;    /* New column for cursor. */
  1260.   
  1261.             /* Skip subclass field. */
  1262.             while (ConGetChar(FALSE) != (UBYTE)';');
  1263.   
  1264.             /* Look for keycode "104" which is left mouse button down.*/
  1265.             if ((ConGetChar(FALSE) == (UBYTE)'1') &&
  1266.                 (ConGetChar(FALSE) == (UBYTE)'0') &&
  1267.                 (ConGetChar(FALSE) == (UBYTE)'4') &&
  1268.                 (ConGetChar(FALSE) == (UBYTE)';'))
  1269.             {
  1270.               mouse_x = xvi_window->MouseX;
  1271.               mouse_y = xvi_window->MouseY;
  1272.               border_left = xvi_window->BorderLeft;
  1273.               border_top = xvi_window->BorderTop;
  1274.   
  1275.   #if DEBUG > 1
  1276.               fprintf(stderr, "  inchar(): Mouse X=%d, Y=%d\n",
  1277.                       xvi_window->MouseX, xvi_window->MouseY);
  1278.   #endif
  1279.               if ((mouse_x > border_left) &&
  1280.                   (mouse_x < 
  1281.                    xvi_window->Width - xvi_window->BorderRight) &&
  1282.                   (mouse_y > border_top) &&
  1283.                   (mouse_y < 
  1284.                    xvi_window->Height - xvi_window->BorderBottom))
  1285.               {
  1286.                 text_width = xvi_window->RPort->TxWidth;
  1287.                 text_height = xvi_window->RPort->TxHeight;
  1288.   
  1289.                 /* Calculate new row and column for cursor. */
  1290.                 new_column = ((mouse_x - border_left) / text_width) + 1;
  1291.                 new_row = ((mouse_y - border_top) / text_height) + 1;
  1292.   
  1293.                 /* If window is slightly larger than an exact modulo  */
  1294.                 /* of row height or column width we need to make sure */
  1295.                 /* the mouse is not in this "extra" area.             */
  1296.                 if (new_column > Columns)
  1297.                   new_column = Columns;
  1298.                 if (new_row > Rows)
  1299.                   new_row = Rows;
  1300.   #ifdef DEBUG
  1301.                 fprintf(stderr,
  1302.                       "  inchar(): Cursor: new_column=%d, new_row=%d\n",
  1303.                         new_column, new_row);
  1304.   #endif
  1305.                 /*####################################################*/
  1306.                 /* THIS FIXES A BUG in mouseclick() where the cursor  */
  1307.                 /* is placed 8 positions to the right of where it     */
  1308.                 /* should be if line numbers are on.                  */
  1309.                 /*####################################################*/
  1310.                 if (Pb(P_number))
  1311.                 {
  1312.                   if (new_column < 9)
  1313.                     new_column = 1;
  1314.                   else
  1315.                     new_column -= 8;
  1316.                 }
  1317.   
  1318.                 /* Do actual cursor movement only if in normal mode. */
  1319.                 if (State == NORMAL)
  1320.                 {
  1321.                   /* Move cursor.  Note that mouseclick() counts  */
  1322.                   /* rows and columns starting at 0 instead of 1. */
  1323.                   mouseclick(new_row - 1, new_column - 1);
  1324.   
  1325.                   /* Update status line for current virtual window. */
  1326.                   show_file_info(curwin);
  1327.                   cursupdate(curwin);
  1328.                   wind_goto(curwin);
  1329.                 }
  1330.               }
  1331.             }
  1332.   
  1333.             /* Wait for end of event sequence.*/
  1334.             while (ConGetChar(FALSE) != (UBYTE)'|');
  1335.   
  1336.           }  /* if...Check for mouse event. */
  1337.           else
  1338.           {
  1339.             /* Look for Window refresh event (if started via CLI). */
  1340.             if (!workbench &&
  1341.                 input_char1 == (UBYTE)'1' &&
  1342.                 input_char2 == (UBYTE)'3' &&
  1343.                 input_char3 == (UBYTE)';')
  1344.             {
  1345.               /* Wait for end of event sequence.*/
  1346.               while (ConGetChar(FALSE) != (UBYTE)'|');
  1347.  
  1348.               /* Just repaint window with CNTL-L. */
  1349.               special_buffer = "\033\014";
  1350.             }
  1351.  
  1352.           }  /* else...Check for mouse event. */
  1353.   
  1354.         }  /* else...Look for Close Window event. */
  1355.   
  1356.       }  /* else...Look for Resize Window event. */
  1357.   
  1358.     }  /* else...Look for Special key. */
  1359.  
  1360.   }  /* while(...) */
  1361.  
  1362.   /* Translate RETURN key so we go to START of next line (normal mode)*/
  1363.   if (input_char == '\r' && State == NORMAL && map_ret_flag)
  1364.   {
  1365.     special_buffer = "\r0";
  1366.   }
  1367.  
  1368.   /* Return any special characters buffered up in this routine first. */
  1369.   if (special_buffer)
  1370.   {
  1371.     input_char = (UBYTE)(*special_buffer++);
  1372.     if (!(*special_buffer))
  1373.       special_buffer = NULL;    /* At end of special buffer. */
  1374.  
  1375. #if DEBUG > 2
  1376.     fprintf(stderr, "  inchar(): Character from special buffer\n");
  1377. #endif
  1378.   }
  1379.  
  1380. #if DEBUG > 1
  1381.   fprintf(stderr, "  inchar(): input_char=0x%02x='%c'\n",
  1382.           input_char, input_char);
  1383. #endif
  1384.   return (input_char);
  1385. }
  1386.  
  1387.  
  1388. /*____________________________________________________________________*/
  1389. /* outchar()                                                          */
  1390. /*   Send a character to display (console device).                    */
  1391. /*                                                                    */
  1392. /* PARMS: c - character to send out.                                  */
  1393. /*____________________________________________________________________*/
  1394. /* FUNCTION */
  1395.  
  1396. void outchar(c)
  1397.   char c;
  1398. {
  1399. #ifdef NO_OUT_BUFFERING
  1400.   ConPutChar(c);
  1401. #else
  1402.   out_buffer[out_buf_index++] = c;    /* Buffer the character. */
  1403.  
  1404.   if (out_buf_index >= OUT_BUFFER_SIZE)
  1405.     flush_output();        /* Flush the buffer if it is full. */
  1406. #endif
  1407. }
  1408.  
  1409. /*____________________________________________________________________*/
  1410. /* outstr()                                                           */
  1411. /*   Send a string to display (console device).                       */
  1412. /*                                                                    */
  1413. /* PARMS: s - character to send out.                                  */
  1414. /*____________________________________________________________________*/
  1415. /* FUNCTION */
  1416.  
  1417. void outstr(s)
  1418.   char *s;
  1419. {
  1420. #ifdef NO_OUT_BUFFERING
  1421.   ConPutStr(s);
  1422. #else
  1423.   int length;
  1424.  
  1425.   /* First make sure there is room in the output buffer. */
  1426.   length = strlen(s);
  1427.   if ((out_buf_index + length) >= OUT_BUFFER_SIZE)
  1428.     flush_output();        /* Flush the buffer. */
  1429.  
  1430.   if (length < OUT_BUFFER_SIZE)
  1431.   {
  1432.     /* Send string to buffer. */
  1433.     (void)strcpy(&out_buffer[out_buf_index], s);
  1434.     out_buf_index += length;
  1435.   }
  1436.   else
  1437.     ConPutStr(s);        /* Buffer not large enough. */
  1438. #endif
  1439. }
  1440.  
  1441.  
  1442. /*____________________________________________________________________*/
  1443. /* flush_output()                                                     */
  1444. /*   Flush any output held in the output buffer to the Amiga screen.  */
  1445. /*____________________________________________________________________*/
  1446. /* FUNCTION */
  1447.  
  1448. void flush_output()
  1449. {
  1450.  
  1451. #if DEBUG > 1
  1452.   fprintf(stderr, "> flush_output(): Prior calls to ttygoto() = %d\n",
  1453.           ttygoto_count);
  1454.   ttygoto_count=0;
  1455.   fprintf(stderr, "  flush_output(): Character count to flush = %d\n",
  1456.           out_buf_index);
  1457. #endif
  1458.  
  1459. #ifndef NO_OUT_BUFFERING
  1460.   /* Skip if out buffer is empty. */
  1461.   if (out_buf_index)
  1462.   {
  1463.     /* Terminate buffer string with NULL. */
  1464.     out_buffer[out_buf_index] = '\000';
  1465.  
  1466.     ConPutStr(out_buffer);    /* Send the buffer out to the display.*/
  1467.     out_buf_index = 0;        /* Set index back to start of buffer. */
  1468.   }
  1469. #endif
  1470.  
  1471. #if DEBUG > 3
  1472.   fprintf(stderr, "< flush_output()\n");
  1473. #endif
  1474.  
  1475. }
  1476.  
  1477.  
  1478. /*____________________________________________________________________*/
  1479. /* erase_display()                                                    */
  1480. /*   Erase the Amiga screen.                                          */
  1481. /*____________________________________________________________________*/
  1482. /* FUNCTION */
  1483.  
  1484. void erase_display()
  1485. {
  1486.   outstr("\014");
  1487.   flush_output();
  1488. }
  1489.  
  1490.  
  1491. /*____________________________________________________________________*/
  1492. /* alert()                                                            */
  1493. /*   Do a visual bell.                                                */
  1494. /*____________________________________________________________________*/
  1495. /* FUNCTION */
  1496.  
  1497. void alert()
  1498. {
  1499.   if (Pb(P_vbell))
  1500.   {
  1501.     outchar('\007');
  1502.     flush_output();    /* Flush the above output. */
  1503.   }
  1504. }
  1505.  
  1506. /*____________________________________________________________________*/
  1507. /* sleep()                                                            */
  1508. /*   Wait a period of time (give up this task).                       */
  1509. /*                                                                    */
  1510. /* PARMS: n - delay in seconds                                        */
  1511. /*____________________________________________________________________*/
  1512. /* FUNCTION */
  1513.  
  1514. void sleep(n)
  1515.   int n;
  1516. {
  1517.   Delay(n * 60);    /* Delay n X 60 ticks (1/60 of second). */
  1518. }
  1519.  
  1520. /*____________________________________________________________________*/
  1521. /* delay()                                                            */
  1522. /*   Wait a short period of time.                                     */
  1523. /*____________________________________________________________________*/
  1524. /* FUNCTION */
  1525.  
  1526. void delay()
  1527. {
  1528.   Delay(12);        /* Delay 1/5 of a second. */
  1529. }
  1530.  
  1531. /*____________________________________________________________________*/
  1532. /* amiga_sys_init()                                                   */
  1533. /*   Initialize the system stuff, like libraries, screen, windows,    */
  1534. /*   font, etc.  This routine takes the place of sys_init().          */
  1535. /*____________________________________________________________________*/
  1536. /* FUNCTION */
  1537.  
  1538. void amiga_sys_init(argc_ptr, argv_ptr)
  1539.   int *argc_ptr;
  1540.   char ***argv_ptr;
  1541. {
  1542.   int index;
  1543.   int error;
  1544.  
  1545.  
  1546. #if DEBUG > 1
  1547.   fprintf(stderr, "> amiga_sys_init(): argc=%d\n", *argc_ptr);
  1548.   for (index = 0; index < *argc_ptr; index++)
  1549.   {
  1550.     fprintf(stderr, "    argv[%d]=\"%s\"\n",
  1551.             index, (*argv_ptr)[index]);
  1552.   }
  1553. #endif
  1554.  
  1555.   /* This determines the default row and column count if starting  */
  1556.   /* up via workbench without any tool type override.  Note that   */
  1557.   /* if starting up via CLI the Rows and Columns variables will be */
  1558.   /* recalculated and changed later.                               */
  1559.   Rows = DEFAULT_ROWS;
  1560.   Columns = DEFAULT_COLS;
  1561.  
  1562.   /* This is the default number of pixels between the left/top edge */
  1563.   /* Amiga Workbench screen and the left/top edge of the new Xvi    */
  1564.   /* window if running Xvi from the Workbench.  These values may be */
  1565.   /* overridden by Xvi tool types "LEFT_EDGE" and "TOP_EDGE".       */
  1566.   left_edge = DFLT_LEFT_EDGE;
  1567.   top_edge = DFLT_TOP_EDGE;
  1568.  
  1569.   name_str = NULL;
  1570.   font_str = NULL;
  1571.   parms_str = NULL;
  1572.  
  1573.   if (*argc_ptr == 0)
  1574.   {
  1575.     /* We started from workbench. */
  1576.  
  1577.     char *temp_str;
  1578.     int parms_argc;
  1579.     int wb_argc;
  1580.     int index_wb;
  1581.  
  1582.     workbench = TRUE;
  1583.     parms_argc = 0;    /* Assume no Workbench PARMS Tool Type. */
  1584.  
  1585.     /* Save the workbench startup stuff. */
  1586.     wb_startup = (struct WBStartup *)(*argv_ptr);
  1587.  
  1588.     wb_argc = wb_startup->sm_NumArgs;    /* Number of workbench args. */
  1589.  
  1590. #if DEBUG > 1
  1591.     /* Workbench only arguments. */
  1592.     fprintf(stderr, "  amiga_sys_init(): Workbench argc=%d\n", wb_argc);
  1593.     for (index = 0; index < wb_argc; index++)
  1594.     {
  1595.       fprintf(stderr, "    Workbench argv[%d]=\"%s\"\n",
  1596.               index, (wb_startup->sm_ArgList + index)->wa_Name);
  1597.     }
  1598.  
  1599.     /* Workbench and Tool Type (from .info file) arguments merged. */
  1600.     fprintf(stderr, "  amiga_sys_init(): _WBArgc=%d\n", _WBArgc);
  1601.     for (index = 0; index < _WBArgc; index++)
  1602.     {
  1603.       fprintf(stderr, "    _WBArgv[%d]=\"%s\"\n",
  1604.               index, _WBArgv[index]);
  1605.     }
  1606. #endif
  1607.  
  1608.     /* Check for any "Tool Types" that we want to apply to xvi. */
  1609.  
  1610.     name_str = XviFindToolType("NAME=");
  1611.  
  1612.     if (temp_str = XviFindToolType("ROWS="))
  1613.     {
  1614.       Rows = atoi(temp_str);    /* Get Rows value. */
  1615.  
  1616.       /* Make sure value is legal. */
  1617.       if ((Rows < MIN_ROWS) || (Rows > MAX_ROWS))
  1618.         Rows = DEFAULT_ROWS;
  1619.     }
  1620.  
  1621.     if (temp_str = XviFindToolType("COLUMNS="))
  1622.     {
  1623.       Columns = atoi(temp_str);    /* Get Columns value. */
  1624.  
  1625.       /* Make sure value is legal. */
  1626.       if ((Columns < MIN_COLS) || (Columns > MAX_COLS))
  1627.         Columns = DEFAULT_COLS;
  1628.     }
  1629.  
  1630.     if (temp_str = XviFindToolType("LEFT_EDGE="))
  1631.     {
  1632.       left_edge = atoi(temp_str);
  1633.  
  1634.       /* Make sure value is reasonable. */
  1635.       if ((left_edge < 0) || (left_edge > MAX_LEFT_EDGE))
  1636.         left_edge = 0;
  1637.     }
  1638.  
  1639.     if (temp_str = XviFindToolType("TOP_EDGE="))
  1640.     {
  1641.       top_edge = atoi(temp_str);
  1642.  
  1643.       /* Make sure value is reasonable. */
  1644.       if ((top_edge < 0) || (top_edge > MAX_TOP_EDGE))
  1645.         top_edge = 0;
  1646.     }
  1647.  
  1648.     if (temp_str = XviFindToolType("FONT="))
  1649.     {
  1650.       /* Need to make a copy of the string because we expect */
  1651.       /* that font_str will be freed by Cleanup_IO().        */
  1652.       font_str = getmem(strlen(temp_str) + 1);
  1653.       (void)strcpy(font_str, temp_str);
  1654.     }
  1655.  
  1656.     if (temp_str = XviFindToolType("PARMS="))
  1657.     {
  1658.       /* Make sure we do not have an empty string. */
  1659.       if (*temp_str)
  1660.       {
  1661.         /* Need to make a copy of the string because we will be */
  1662.         /* modifying it.  Note that parms_str will be freed by  */
  1663.         /* sys_exit().                                          */
  1664.         parms_str = getmem(strlen(temp_str) + 1);
  1665.         (void)strcpy(parms_str, temp_str);
  1666.  
  1667.         /* Count the number of arguments specified by "PARMS". */
  1668.         /* Expect that arguments are separated by one or more  */
  1669.         /* spaces (tabs will not work).                        */
  1670.         for (temp_str = parms_str + 1, parms_argc = 1; *temp_str;
  1671.              temp_str++)
  1672.         {
  1673.           /* Look for a non-space after a space to indicate */
  1674.           /* that we have another argument.                 */
  1675.           if ((*(temp_str - 1) == ' ') && (*temp_str != ' '))
  1676.             parms_argc++;
  1677.         }
  1678. #if DEBUG > 2
  1679.         fprintf(stderr, "  amiga_sys_init(): parms_str=\"%s\"\n",
  1680.                 parms_str);
  1681. #endif
  1682.  
  1683.       }
  1684.     }
  1685.  
  1686.     /* Now fix up real argc and argv. */
  1687.  
  1688.     /* Calculate total number of arguments (will be at least 1). */
  1689.     *argc_ptr = wb_argc + parms_argc;
  1690.  
  1691.     /* Note that this memory will be freed by sys_exit().  Also,     */
  1692.     /* we ask for an extra pointer location to store an ending NULL. */
  1693.     *argv_ptr = getmem(sizeof(char *) * ((*argc_ptr) + 1));
  1694.  
  1695.     /* Always have first workbench argument, which is program name. */
  1696.     /* Get it from SAS "C" workbench environment so we get full     */
  1697.     /* path name.                                                   */
  1698.     (*argv_ptr)[0] = _WBArgv[0];
  1699.  
  1700.     index = 1;
  1701.  
  1702.     /* Add any PARMS Tool Type arguments to the argv list here. */
  1703.     if (parms_str)
  1704.       (*argv_ptr)[index++] = parms_str;    /* First PARMS argument. */
  1705.  
  1706.     for (temp_str = parms_str + 1, parms_argc = 1; *temp_str;
  1707.          temp_str++)
  1708.     {
  1709.       /* Again look for a non-space after a space */
  1710.       /* to find each argument.                   */
  1711.       if ((*(temp_str - 1) == ' ') && (*temp_str != ' '))
  1712.       {
  1713.         *(temp_str - 1) = '\000';    /* Terminate prior argument. */
  1714.         if (index < *argc_ptr)        /* Check argc just to make sure. */
  1715.           (*argv_ptr)[index++] = temp_str;    /* Get next argument. */
  1716.       }
  1717.     }
  1718.  
  1719.     /* Add any "files to edit" workbench arguments to argv list.  */
  1720.     /* Get them from SAS "C" workbench environment so we get full */
  1721.     /* path name for any file(s) to edit.                         */
  1722.  
  1723.     /* Get index into _WBArgv where first "file to edit" argument is. */
  1724.     index_wb = (_WBArgc - wb_argc) + 1;
  1725.  
  1726.     while(index_wb < _WBArgc)
  1727.     {
  1728.       if (index < *argc_ptr)        /* Check argc just to make sure. */
  1729.         (*argv_ptr)[index++] = _WBArgv[index_wb++];
  1730.     }
  1731.  
  1732.     /* Put a terminating NULL at end of argv list.*/
  1733.     (*argv_ptr)[index] = NULL;
  1734.  
  1735.     /* Save the argc and argv POINTERS passed in */
  1736.     /* so we can use them at exit time.          */
  1737.     saved_argc_ptr = argc_ptr;
  1738.     saved_argv_ptr = argv_ptr;
  1739.   }
  1740.   else
  1741.   {
  1742.     /* We started from CLI. */
  1743.     workbench = FALSE;
  1744.   }
  1745.  
  1746.   /* Now do the I/O and Amiga windowing initialization. */
  1747.   if (error = Init_IO())
  1748.   {
  1749.     Cleanup_IO(error);    /* Something is wrong, so bail out. */
  1750.     sleep(15);        /* Wait 15 seconds for any output to be seen. */
  1751.     exit(error);
  1752.   }
  1753.  
  1754. #ifdef DEBUG
  1755.   fprintf(stderr, "< amiga_sys_init(): argc=%d\n", *argc_ptr);
  1756.   for (index = 0; index < *argc_ptr; index++)
  1757.   {
  1758.     fprintf(stderr, "    argv[%d]=\"%s\"\n",
  1759.             index, (*argv_ptr)[index]);
  1760.   }
  1761.   /* Wait 4 seconds so output can be seen if running from CLI. */
  1762.   if (!workbench)
  1763.     sleep(4);
  1764. #endif
  1765. }
  1766.  
  1767.  
  1768. /*____________________________________________________________________*/
  1769. /* sys_exit()                                                         */
  1770. /*   Exit the program to the system, cleaning up any system stuff.    */
  1771. /*                                                                    */
  1772. /* PARMS: r - Return code to return to the system.                    */
  1773. /*____________________________________________________________________*/
  1774. /* FUNCTION */
  1775.  
  1776. void sys_exit(r)
  1777.   int r;
  1778. {
  1779.   tty_goto(Rows-1, 0);
  1780.   outchar('\n');
  1781.   flush_output();    /* Flush the above remaining output. */
  1782.   if (r && !workbench)
  1783.     sleep(4);        /* Wait for any displayed errors to be seen. */
  1784.  
  1785.   Cleanup_IO(0);    /* Do normal cleanup. */
  1786.  
  1787.  
  1788.   if (workbench)
  1789.   {
  1790.     /* Free any memory from getmem() calls in amiga_sys_init(). */
  1791.     if(parms_str)
  1792.       free(parms_str);
  1793.     free(*saved_argv_ptr);
  1794.  
  1795.     /* Now put back the original values into argv and argc. */
  1796.     *saved_argv_ptr = (char *)wb_startup;
  1797.     *saved_argc_ptr = 0;
  1798.   }
  1799.  
  1800.   exit(r);
  1801. }
  1802.  
  1803.  
  1804. /*____________________________________________________________________*/
  1805. /* tty_goto()                                                         */
  1806. /*   Send the cursor to "row_num" and "col_num" position on the       */
  1807. /*   screen.                                                          */
  1808. /*                                                                    */
  1809. /*   A string containing the appropiate control sequence is created   */
  1810. /*   and then sent to outstr().  This 9 character string contains:    */
  1811. /*   "\233###;###H" where \233 is the <CSI>, the first ### is the row */
  1812. /*   number as decimal digits and the second ### is the column number.*/
  1813. /*                                                                    */
  1814. /* PARMS: row_num - row number                                        */
  1815. /*        col_num - column number                                     */
  1816. /*____________________________________________________________________*/
  1817. /* FUNCTION */
  1818.  
  1819. void tty_goto(row_num, col_num)
  1820.   int row_num;
  1821.   int col_num;
  1822. {
  1823.   int remainder;
  1824.  
  1825.   /* 11-character array of characters to hold 10-character string */
  1826.   /* plus terminating NULL.                                       */
  1827.   char str[10] = {'\233',0,0,0,';',0,0,0,'H','\000'};
  1828.  
  1829. #if DEBUG > 2
  1830.   fprintf(stderr, "> tty_goto(): row_num=%d  col_num=%d\n",
  1831.    row_num, col_num);
  1832. #endif
  1833.  
  1834. #if DEBUG > 1
  1835.   ttygoto_count++;
  1836. #endif
  1837.  
  1838.   /* Correct for row/column numbering starting at zero. */
  1839.   row_num++;
  1840.   col_num++;
  1841.  
  1842.   /* Make sure we don't go past 999 limit. */
  1843.   if (row_num > 999)
  1844.     row_num = 999;
  1845.   if (col_num > 999)
  1846.     col_num = 999;
  1847.  
  1848.   /* Handle the row digits. */
  1849.   str[1] = '0' + (row_num / 100);
  1850.   str[2] = '0' + ((remainder = row_num % 100) / 10);
  1851.   str[3] = '0' + (remainder % 10);
  1852.  
  1853.   /* Handle the column digits. */
  1854.   str[5] = '0' + (col_num / 100);
  1855.   str[6] = '0' + ((remainder = col_num % 100) / 10);
  1856.   str[7] = '0' + (remainder % 10);
  1857.  
  1858.   outstr(str);        /* Send string to screen. */
  1859.  
  1860. #if DEBUG > 3
  1861.               /* Print string but skip leading ESC. */
  1862.   fprintf(stderr, "< tty_goto(): str=\"%s\"\n", &str[1]);
  1863. #endif
  1864. }
  1865.  
  1866.  
  1867. /*____________________________________________________________________*/
  1868. /* sys_pipe()                                                         */
  1869. /*   Used for the ! command.  The first parameter is the command to   */
  1870. /*   invoke, while the second and third are functions which should    */
  1871. /*   be called with an open file pointer in order to write out old,   */
  1872. /*   or read in new lines, respectively.                              */
  1873. /*                                                                    */
  1874. /*   On the Amiga this function might have been implemented using the */
  1875. /*   PIPE: handler but it would take almost as much work and there    */
  1876. /*   might be collisions with other applications using the same named */
  1877. /*   pipes.  Also, some commands might need the whole file present as */
  1878. /*   input wheras PIPE: has a 4K buffer that is a stream.             */
  1879. /*                                                                    */
  1880. /* PARMS: command           Command to invoke.                        */
  1881. /*        file_write_funct(FILE *)  Function to write old lines to    */
  1882. /*                                   temp file.                       */
  1883. /*        file_read_funct(FILE *)   Function to read new lines from   */
  1884. /*                                   temp file.                       */
  1885. /* RETURNS: TRUE if all succeeds.                                     */
  1886. /*____________________________________________________________________*/
  1887. /* FUNCTION */
  1888.  
  1889. bool_t sys_pipe(command, file_write_funct, file_read_funct)
  1890.   char *command;
  1891.   int (*file_write_funct)();
  1892.   long (*file_read_funct)();
  1893. {
  1894.   char buffer[120];
  1895.   char tmp_infname[L_tmpnam];
  1896.   char tmp_outfname[L_tmpnam];
  1897.   FILE *tmp_infile;
  1898.   FILE *tmp_outfile;
  1899.   int sys_error;
  1900.   int error = 0;          /* Assume success. */
  1901.   bool_t ret_val = TRUE;  /* Assume success. */
  1902.  
  1903.  
  1904. #if DEBUG > 1
  1905.   fprintf(stderr, "> sys_pipe(): command=%s\n", command);
  1906. #endif
  1907.  
  1908.   /* Skip any leading blanks in command. */
  1909.   command = stpblk(command);
  1910.  
  1911.   /* Check for null command. */
  1912.   if (!(*command))
  1913.     goto exit_pt;
  1914.  
  1915.   /* Get a unique, temporary filenames for input and output. */
  1916.   (void)strcpy(tmp_infname, tmpnam(NULL));
  1917.   (void)strcpy(tmp_outfname, tmpnam(NULL));
  1918.  
  1919. #if DEBUG > 1
  1920.   fprintf(stderr, "  sys_pipe(): tmp_infname=\"%s\"\n", tmp_infname);
  1921.   fprintf(stderr, "  sys_pipe(): tmp_outfname=\"%s\"\n",
  1922.           tmp_outfname);
  1923. #endif
  1924.  
  1925.   /* Open input temp file for creating, writing, then reading. */
  1926.   if (tmp_infile = fopen(tmp_infname, "w+"))
  1927.   {
  1928.     /* Write "old" lines into input temp file. */
  1929.     (void)((file_write_funct)(tmp_infile));
  1930.  
  1931.     /* Close input temp file. */ 
  1932.     if (!fclose(tmp_infile))
  1933.     {
  1934.       /* Send the command getting/sending I/O from/to temporary files.*/
  1935.       sprintf(buffer, "%s %s %s", command, tmp_infname, tmp_outfname);
  1936.       if (!(sys_error = system(buffer)))
  1937.       {
  1938.         /* Open output temp file for reading. */
  1939.         if (tmp_outfile = fopen(tmp_outfname, "r"))
  1940.         {
  1941.           /* Read "new" lines from output temp file. */
  1942.           if (((file_read_funct)(tmp_outfile)) == -1)
  1943.             error = 1;
  1944.  
  1945.           /* Close output temp file. */ 
  1946.           if (fclose(tmp_outfile))
  1947.             error = 2;    /* Can't close output file. */
  1948.         }
  1949.         else        /* Can't open output file. */
  1950.           error = 3;
  1951.  
  1952.         /* Remove the output temp file. */
  1953.         if (remove(tmp_outfname))
  1954.           error = 4;    /* Can't remove output file. */
  1955.       }
  1956.       else        /* Command failed. */
  1957.         error = 5;
  1958.     }
  1959.     else        /* Can't close input file. */
  1960.       error = 6;
  1961.  
  1962.     /* Remove the input temp file. */
  1963.     if (remove(tmp_infname))
  1964.       error = 7;    /* Can't remove input file. */
  1965.   }
  1966.   else  /* if...fopen(tmp_infname...) */
  1967.     error = 8;        /* Can't open input file. */
  1968.  
  1969.  
  1970.   /* Check for any errors. */
  1971.   if (error)
  1972.   {
  1973. #ifdef DEBUG
  1974.     char *error_str;
  1975.     switch (error)
  1976.     {
  1977.       case 1:
  1978.         error_str = "(file_read_funct)() failed";
  1979.         break;
  1980.       case 2:
  1981.         error_str = "Can't close output temp file";
  1982.         break;
  1983.       case 3:
  1984.         error_str = "Can't open output temp file";
  1985.         break;
  1986.       case 4:
  1987.         error_str = "Can't remove output temp file";
  1988.         break;
  1989.       case 5:
  1990.         error_str = "Command failed";
  1991.         break;
  1992.       case 6:
  1993.         error_str = "Can't close input temp file";
  1994.         break;
  1995.       case 7:
  1996.         error_str = "Can't remove input temp file";
  1997.         break;
  1998.       case 8:
  1999.         error_str = "Can't open input temp file";
  2000.         break;
  2001.       default:
  2002.         error_str = "???";
  2003.     }
  2004.     fprintf(stderr, "  sys_pipe(): buffer=\"%s\"\n", buffer);
  2005.     fprintf(stderr, "  sys_pipe(): %s\n", error_str);
  2006. #endif
  2007.     ret_val = FALSE;
  2008.   }
  2009.  
  2010. exit_pt:
  2011.  
  2012. #if DEBUG > 1
  2013.   fprintf(stderr, "< sys_pipe(): sys_error=%d, ret_val=%d\n",
  2014.           sys_error, ret_val);
  2015. #endif
  2016.   return(ret_val);
  2017. }
  2018.  
  2019.  
  2020. /*____________________________________________________________________*/
  2021. /* call_system()                                                      */
  2022. /*   Invoke the given command sending output to the xvi window.       */
  2023. /*                                                                    */
  2024. /* PARMS: command   Command to invoke.                                */
  2025. /* RETURNS: 0 if all succeeds.                                        */
  2026. /*____________________________________________________________________*/
  2027. /* FUNCTION */
  2028.  
  2029. int call_system(command)
  2030.   char *command;
  2031. {
  2032.   char buffer[120];
  2033.   char *tmp_fname;
  2034.   FILE *tmp_file;
  2035.   int ret_val = 0;  /* Assume success. */
  2036.  
  2037. #if DEBUG > 1
  2038.   fprintf(stderr, "> call_system(): command=%s\n", command);
  2039. #endif
  2040.  
  2041.   /* Skip any leading blanks in command. */
  2042.   command = stpblk(command);
  2043.  
  2044.   /* Check for null command. */
  2045.   if (!(*command))
  2046.     goto exit_pt;
  2047.  
  2048.   /* Get a unique, temporary filename. */
  2049.   tmp_fname = tmpnam(NULL);
  2050.  
  2051. #ifdef DEBUG
  2052.   fprintf(stderr, "  call_system(): tmp_fname=\"%s\"\n", tmp_fname);
  2053. #endif
  2054.  
  2055.   /* Send the command redirecting output to temporary file. */
  2056.   sprintf(buffer, "%s >%s", command, tmp_fname);
  2057.   if (ret_val = system(buffer))
  2058.   {
  2059.     sprintf(buffer, "\nERROR: %s command failed\n", command);
  2060.     outstr(buffer);
  2061.     goto exit_pt;
  2062.   }
  2063.  
  2064.   /* Copy temporary file to display. */
  2065.   if (!(tmp_file = fopen(tmp_fname, "r")))
  2066.   {
  2067.     sprintf(buffer, "\nERROR: Cannot open temp file: %s\n", tmp_fname);
  2068.     outstr(buffer);
  2069.     ret_val = -1;
  2070.     goto exit_pt;
  2071.   }
  2072.   while (fgets(buffer, 120, tmp_file))
  2073.     outstr(buffer);
  2074.   if (fclose(tmp_file))
  2075.   {
  2076.     sprintf(buffer, "\nERROR: Cannot close temp file: %s\n", tmp_fname);
  2077.     outstr(buffer);
  2078.     ret_val = -2;
  2079.     goto exit_pt;
  2080.   }
  2081.  
  2082.   /* Remove the temporary file. */
  2083.   if (remove(tmp_fname))
  2084.   {
  2085.     sprintf(buffer,"\nERROR: Cannot remove temp file: %s\n", tmp_fname);
  2086.     outstr(buffer);
  2087.     ret_val = -3;
  2088.     goto exit_pt;
  2089.   }
  2090.  
  2091. exit_pt:
  2092.   flush_output();    /* Flush any output from above. */
  2093.  
  2094. #if DEBUG > 1
  2095.   fprintf(stderr, "< call_system(): ret_val=%d\n", ret_val);
  2096. #endif
  2097.   return(ret_val);
  2098. }
  2099.  
  2100.  
  2101. /*____________________________________________________________________*/
  2102. /* call_shell()                                                       */
  2103. /*   Invoke a shell.  On the Amiga this creates a new shell attached  */
  2104. /*   to a new window, which is independent of the existing xvi        */
  2105. /*   session.  The SHELL variable is checked in this routine even     */
  2106. /*   though the same stuff is in "command" if SHELL is defined,       */
  2107. /*   becuase we want to use a default shell command if SHELL is not   */
  2108. /*   defined.                                                         */
  2109. /*                                                                    */
  2110. /* PARMS: command   Shell to invoke. (unused)                         */
  2111. /* RETURNS: 0 if all succeeds.                                        */
  2112. /*____________________________________________________________________*/
  2113. /* FUNCTION */
  2114.  
  2115. int call_shell(command)
  2116.   char *command;
  2117. {
  2118.   char *shell_str;
  2119.   char *shell_start_str;
  2120.   char *tmp_str = NULL;    /* No temp string to start. */
  2121.   int ret_val = 0;    /* Assume success. */
  2122.   bool_t default_shell = FALSE;
  2123.  
  2124. #if DEBUG > 1
  2125.   fprintf(stderr, "> call_shell(): command=%s\n", command);
  2126. #endif
  2127.  
  2128.   /* Use the SHELL environment variable if it exists. */
  2129.   if (!(shell_str = getenv("SHELL")))
  2130.   {
  2131.     default_shell = TRUE;  /* Can't free the default shell string.*/
  2132.     shell_str = DFLT_SHELL;
  2133.   }
  2134.  
  2135.   /* Use the XVISHSTART environment variable, if it exists, */
  2136.   /* to get an xvi specific shell startup file.             */
  2137.   if (shell_start_str = getenv("XVISHSTART"))
  2138.   {
  2139.     tmp_str = getmem(strlen(shell_str) + strlen(shell_start_str) + 10);
  2140.     sprintf(tmp_str, "%s FROM %s", shell_str, shell_start_str);
  2141.  
  2142.     /* Free any memory from getenv(). */
  2143.     if (!default_shell)
  2144.       free(shell_str);
  2145.     free(shell_start_str);
  2146.  
  2147.     default_shell = FALSE;
  2148.     shell_str = tmp_str;
  2149.   }
  2150.  
  2151. #if DEBUG > 1
  2152.   fprintf(stderr, "  call_shell(): shell_str=\"%s\"\n", shell_str);
  2153. #endif
  2154.  
  2155.   ret_val = system(shell_str);    /* Make a new shell. */
  2156.  
  2157.   /* Free any remaining memory gotten from getmem() or getenv(). */
  2158.   if (!default_shell)
  2159.     free(shell_str);
  2160.  
  2161. #if DEBUG > 1
  2162.   fprintf(stderr, "< call_shell(): ret_val=%d\n", ret_val);
  2163. #endif
  2164.   return(ret_val);
  2165. }
  2166.  
  2167. /*____________________________________________________________________*/
  2168. /* sys_startv()                                                       */
  2169. /*   Switch to "visual" mode.  (not used)                             */
  2170. /*____________________________________________________________________*/
  2171. /* FUNCTION */
  2172.  
  2173. void sys_startv()
  2174. {
  2175. }
  2176.  
  2177. /*____________________________________________________________________*/
  2178. /* sys_endv()                                                         */
  2179. /*   Switch out of "visual" mode.  (not used)                         */
  2180. /*____________________________________________________________________*/
  2181. /* FUNCTION */
  2182.  
  2183. void sys_endv()
  2184. {
  2185. }
  2186.  
  2187.  
  2188. /*____________________________________________________________________*/
  2189. /* can_write()                                                        */
  2190. /*   Determines if file "filename" can be written, i.e. if a call to  */
  2191. /*   fopenwb(filename) will succeed.                                  */
  2192. /*                                                                    */
  2193. /* PARMS: filename  File to check.                                    */
  2194. /* RETURNS: TRUE if the file can be written to.                       */
  2195. /*____________________________________________________________________*/
  2196.  
  2197. /* FUNCTION */
  2198. bool_t can_write(filename)
  2199.   char  *filename;
  2200. {
  2201.   bool_t ret_value;
  2202.  
  2203. #if DEBUG > 1
  2204.   fprintf(stderr, "> can_write(): filename=\"%s\"\n", filename);
  2205. #endif
  2206.  
  2207.   /* If file does not exist or if file */
  2208.   /* exists but is writable we're OK.  */
  2209.   if (access(filename, 0) == -1 || access(filename, 2) == 0)
  2210.     ret_value = TRUE;
  2211.   else
  2212.     ret_value = FALSE;
  2213.  
  2214. #if DEBUG > 1
  2215.   fprintf(stderr, "< can_write(): ret_value=%d\n", ret_value);
  2216. #endif
  2217.   return (ret_value);
  2218. }
  2219.  
  2220.  
  2221. /*____________________________________________________________________*/
  2222. /* set_colour()                                                       */
  2223. /*   Set text, commands, system, etc colors.                          */
  2224. /*   Note: Do not try to blank cursor in this routine.                */
  2225. /*                                                                    */
  2226. /*   This routine is currently unused.                                */
  2227. /*                                                                    */
  2228. /* PARMS: color  Color to set.                                        */
  2229. /*____________________________________________________________________*/
  2230.  
  2231. /* FUNCTION */
  2232. void set_colour(color)
  2233.   int color;
  2234. {
  2235.   int style;
  2236.   int bg;
  2237.   int fg;
  2238.  
  2239.   /* Initialize to "Plain text", BG=grey, FG=black. */
  2240.   char color_str[10] =
  2241.     {'\233','0',';','4','0',';','3','1','m','\000'};
  2242.  
  2243. #if DEBUG > 1
  2244.   fprintf(stderr, "> set_colour(): color=%04o (Octal)\n", color);
  2245. #endif
  2246.  
  2247.   switch (style = color >> 6)
  2248.   {
  2249.     case 0:
  2250.     case 1:
  2251.     case 3:
  2252.     case 4:
  2253.     case 7:
  2254.       bg = (color >> 3) & 0x0007;
  2255.       fg = color & 0x0007;
  2256.       color_str[1] = '0' + style;    /* Set the style. */
  2257.       color_str[4] = '0' + bg;        /* Set the background color. */
  2258.       color_str[7] = '0' + fg;        /* Set the foreground color. */
  2259.       outstr(color_str);        /* Send it to the console. */
  2260.       break;
  2261.  
  2262.     default:
  2263.       color_str[0] = '\000';
  2264.   }
  2265.  
  2266. #if DEBUG > 1
  2267.   /* Skip <CSI> when printing. */
  2268.   if (color_str[0])
  2269.     fprintf(stderr, "< set_colour(): color_str=\"%s\"\n", color_str+1);
  2270.   else
  2271.     fprintf(stderr, "< set_colour(): Color handling disabled\n");
  2272. #endif
  2273. }
  2274.  
  2275.  
  2276. /*____________________________________________________________________*/
  2277. /* tempfname()                                                        */
  2278. /*   Create a unique filename, possibly using "srcname" as a base,    */
  2279. /*   for use by do_preserve() to create a backup file for the file    */
  2280. /*   named "srcname".  On the Amiga this filename should NOT have a   */
  2281. /*   path of "T:" (directory for temporary files) since this is in    */
  2282. /*   RAM: and will be lost with a system crash defeating the purpose  */
  2283. /*   of do_preserve().                                                */
  2284. /*                                                                    */
  2285. /*   WARNING: The string returned must  have been allocated using     */
  2286. /*   malloc() or a derivative; NULL may be returned if there is no    */
  2287. /*   more memory available.                                           */
  2288. /*                                                                    */
  2289. /* PARMS: srcname  Basename for unique filename.                      */
  2290. /* RETURNS: TRUE if the file can be written to.                       */
  2291. /*____________________________________________________________________*/
  2292.  
  2293. /* FUNCTION */
  2294. char *tempfname(srcname)
  2295.   char *srcname;
  2296. {
  2297.   char *fname_str = NULL;
  2298.   char *tmp_str;
  2299.  
  2300. #ifdef DEBUG
  2301.   fprintf(stderr, "> tempfname(): srcname=\"%s\"\n", srcname);
  2302. #endif
  2303.  
  2304.   /* Allocate memory for the unique filename string. */
  2305.   if (fname_str = getmem(L_tmpnam + strlen(srcname)))
  2306.   {
  2307.     tmp_str = tmpnam(NULL);  /* Get a unique filename. */
  2308.  
  2309.     /* Replace "T:" at start of string from tmpnam() */
  2310.     /* with "__" and append it to basename.          */
  2311.     sprintf(fname_str, "%s__%s", srcname, tmp_str + 2);
  2312.   }
  2313.  
  2314. #ifdef DEBUG
  2315.   fprintf(stderr, "< tempfname(): fname_str=\"%s\"\n", fname_str);
  2316. #endif
  2317.   return(fname_str);
  2318. }
  2319.  
  2320.  
  2321. /*____________________________________________________________________*/
  2322. /* exists()                                                           */
  2323. /*   Check for existance of a file.                                   */
  2324. /*                                                                    */
  2325. /* PARMS: filename  File to check for existance.                      */
  2326. /* RETURNS: TRUE if the file exists.                                  */
  2327. /*____________________________________________________________________*/
  2328.  
  2329. /* FUNCTION */
  2330. bool_t exists(char *filename)
  2331. {
  2332.   BPTR lock;
  2333.   bool_t retval;
  2334.  
  2335. #if DEBUG > 1
  2336.   fprintf(stderr, "> exists(): filename=\"%s\"\n", filename);
  2337. #endif
  2338.  
  2339.   if ((lock = findpath(filename)) == ((BPTR)-1))
  2340.     retval = FALSE;
  2341.   else
  2342.   {
  2343.     UnLock(lock);
  2344.     retval = TRUE;
  2345.   }
  2346.  
  2347. #if DEBUG > 1
  2348.   fprintf(stderr, "< exists(): retval=%d\n", retval);
  2349. #endif
  2350.   return (retval);
  2351. }
  2352.  
  2353.  
  2354. /*____________________________________________________________________*/
  2355. /* amiga_version()                                                    */
  2356. /*   Put up a requester with copyright and version information.       */
  2357. /*____________________________________________________________________*/
  2358.  
  2359. /* FUNCTION */
  2360. void amiga_version()
  2361. {
  2362. #ifdef OLD_AMIGA_OS /*________________________________________________*/
  2363.   /* For pre-2.0 Amiga OS.  Last two numbers are for pre-2.0 OS       */
  2364.   /* requestor size parameters.  Only need negative-text for 1 button.*/
  2365.   if (AutoRequest(xvi_window, xvi_ver_bodytext,
  2366.                   NULL, xvi_ver_negtext, 0, 0, 630, 50))
  2367. #else /*______________________________________________________________*/
  2368.   /* For 2.0 Amiga OS or later. */
  2369.   (void) EasyRequestArgs(xvi_window, xvi_ver_requester, NULL, NULL);
  2370. #endif /*_____________________________________________________________*/
  2371.  
  2372.   repaint = TRUE;
  2373. }
  2374.  
  2375. /* End of file________________________________________________________*/
  2376.